package org.spring.springboot.entity;

import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spring.springboot.util.SpringContextUtils;
import org.spring.springboot.mapper.ScheduleInstanceMapper;
import org.spring.springboot.util.MLock.MLock;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.util.Objects;

@Data
public class SchedulingRunnable implements Runnable {

    private static final Logger logger = LoggerFactory.getLogger(SchedulingRunnable.class);

    private String beanName;

    private String methodName;

    private String cronKey;

    private Integer jobId;

    private ScheduleInstanceMapper mapper;

    public SchedulingRunnable(String beanName, String methodName, String cronKey, Integer jobId) {
        this.beanName = beanName;
        this.methodName = methodName;
        this.cronKey = cronKey;
        this.jobId = jobId;
    }


    @Override
    public void run() {
        long startTime = System.currentTimeMillis();
        MLock mLock = new MLock(cronKey);
        boolean lockResult = mLock.tryLock();
        if(!lockResult){
            System.out.println("未能获取到锁");
            return;
        }
        String executeStatus = "SUCCESS";
        String errorMessage = null;
        try {
            Object target = SpringContextUtils.getBean(beanName);
            Method method = target.getClass().getDeclaredMethod(methodName);
            ReflectionUtils.makeAccessible(method);
            method.invoke(target);
        } catch (Exception ex) {
            executeStatus = "FAIL";
            int length = Math.min(ex.getCause().toString().length(),1000);
            errorMessage = ex.getCause().toString().substring(0,length);
        } finally {
            Integer times = Math.toIntExact(System.currentTimeMillis() - startTime);
            ScheduleInstance scheduleInstance = ScheduleInstance.builder()
                    .jobId(jobId)
                    .cronKey(cronKey)
                    .beanName(beanName)
                    .methodName(methodName)
                    .executeStatus(executeStatus)
                    .errorMessage(errorMessage)
                    .executeTimes(times)
                    .build();
            mapper.insertOne(scheduleInstance);
            mLock.unlock();
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        SchedulingRunnable that = (SchedulingRunnable) o;
        return this.cronKey.equals(that.cronKey);
    }

    @Override
    public int hashCode() {
        return Objects.hash(cronKey);
    }
}